/**
 * @fileOverview 通用功能库。
 * @version 0.9.0.1
 * @author Direct Guo
 */
/**
 * 通用功能库。
 * @description 不需要new，直接调用。
 * @class
 * @example
 * 2011.3.7 0.91版更新内容
 * * 修正isOWB判断机制
 * * 修正ptest的某些bug
 * 2011.1.29 0.9版更新内容
 * * 新增common.ptest性能测试工具
 * * 新增common.logable打印开关
 *
 * common.isOWB
 * common.keyCodeArr.xxx 或者 keyCodeArr.xxx
 * common.log(data1,data2,...);
 * common.key.init();
 * common.key.end();
 * common.key.change(obj);
 * common.key.bind(obj);
 * common.key.unbind(obj);
 */
(function(){
	
	var isOWB = /.*chrome.*/i.test(navigator.userAgent) ? false : true;
	
    window.common = {
        /**
         * 性能测试工具。
         * @description 不需要new，直接调用。
         * @class
         * @example
         * 1.如果在页面开头定义了全局的startTime变量(格式如下)，则会自动将其作为开始时间，如果无则自动获取当前时间作为开始时间。
         * 2.可以建立多个独立的报表，分别计算
         *
         * ..页面开头...
         * window.startTime = {
         *     t: new Date(),
         *     n: "页面开始!"
         * }
         * ...加载common.js...
         * ....
         * common.ptest.setPoint("开始加载")
         * ....code....
         * common.ptest.setPoint("模块A 开始")
         * ....模块a...
         * common.ptest.setPoint("模块A 结束")
         * common.ptest.printList()
         *
         * 控制台会打印如下信息：
         * 	 | 表：defaultList
         *   | 时间				间隔	累计	信息
         * ---------------------------------------------------
         * 0 | 1296289696.371	0	0	页面开始!:
         * 1 | 1296289696.383	12	12	开始加载:
         * 2 | 1296289696.454	71	83	模块A 开始:
         * 3 | 1296289696.465	11	94	模块A 结束:
         * ---------------------------------------------------
         *
         */
        ptest: {
            lists: {
                defaultList: window.startTime ? [window.startTime] : [{
                    t: new Date(),
                    n: "页面开始!"
                }]
            },
            /**
             * 在制定列表设置一个记录点
             * @description 记录程序执行到此点的系统时间和说明
             * @public
             * @param {string} msg 此条时间记录的说明
             * @param {string} ln 列表名，此字符串必须遵循变量命名规则；如果不指定则加入默认列表；如果列表不存在则新建列表；
             * @returns {boolean} 操作是否成功
             * @example
             * common.ptest.setPoint("模块A 结束")
             * common.ptest.setPoint("模块C 开始","list2")
             */
            setPoint: function(msg, ln){
                ln = ln || "defaultList";
                var list = this.lists[ln] || (this.lists[ln] = []);
                list.push({
                    n: msg,
                    t: new Date()
                })
                return true;
            },
            /**
             * 打印记录表
             * @description 打印并返回指定列表的报表字符串
             * @public
             * @param {string} ln 列表名，此字符串必须遵循变量命名规则；如果不指定则打印默认列表；
             * @param {boolean} nolog 如果为真，则不打印只返回
             * @returns {string} 操作成功则返回报表字符串，可以直接打印；操作失败则返回false
             * @example
             * common.ptest.printList()
             * common.ptest.printList("list2")
             */
            printList: function(ln, nolog){
                ln = ln || "defaultList";
                var list = this.lists[ln];
                if (!list) {
                    return false;
                }
                var l, total = 0, r = "  | 表：" + ln + "\n  | 时间(s)\t\t间隔(ms)\t累计(ms)\t信息\n---------------------------------------------------\n";
                for (var i = 0; i < list.length; i++) {
                    var t = list[i];
                    var dur = l ? t.t - l : 0;
                    total += dur;
                    r = r + i + " | " + t.t / 1000 + "\t" + dur + "\t" + total + "\t" + t.n + ":\n";
                    l = t.t;
                }
                r = r + "---------------------------------------------------";
                nolog || common.log(r);
                return r;
            },
            /**
             * 清空记录表
             * @description 清空制定的记录表
             * @public
             * @param {string} ln 列表名，此字符串必须遵循变量命名规则；如果不指定则清空默认列表；
             * @returns {boolean} 操作成功则返回true
             * @example
             * common.ptest.clearList()
             * common.ptest.clearList("list2")
             */
            clearList: function(ln){
                ln = ln || "defaultList";
                this.lists[ln] && (this.lists[ln] = [])
                return true;
            }
        },
        /**
         * 判定运行环境是否为owb
         * @public
         * @example
         * if(common.isOWB){
         *  alert("现在运行在OWB上");
         * }
         */
        isOWB: isOWB,
        /**
         * 按键码数组,自动适应owb或者pc
         * @public
         * @example
         * keyPress = function(key){
         *  switch (key) {
         *   case keyCodeArr.up:
         *    ...
         *    break;
         *   case keyCodeArr.down:
         *    ...
         *    break;
         *  }
         *}
         */
        keyCodeArr: isOWB ? {
            //OWB
            'left': 37,
            'up': 38,
            'right': 39,
            'down': 40,
            'enter': 13,
            'num0': 48,
            'num1': 49,
            'num2': 50,
            'num3': 51,
            'num4': 52,
            'num5': 53,
            'num6': 54,
            'num7': 55,
            'num8': 56,
            'num9': 57,
            'exit': 74,
            'fastplay': 69,
            'fastback': 66,
            'menu': 77,
            'pageUp': 33,
            'pageDn': 34,
            'volUp': 107,
            'volDn': 109,
            'play': 76,
            'pause': 19,
            'stop': 79,
            'playNext': 78,
            'playPrev': 86,
            'mute': 85,
            'red': 112,
            'green': 113,
            'yellow': 114,
            'blue': 115
        } : {
            //PC
            'left': 37,
            'up': 38,
            'right': 39,
            'down': 40,
            'enter': 13,
            'num0': 48,
            'num1': 49,
            'num2': 50,
            'num3': 51,
            'num4': 52,
            'num5': 53,
            'num6': 54,
            'num7': 55,
            'num8': 56,
            'num9': 57,
            'exit': 27,
            'fastplay': 101,
            'fastback': 98,
            'menu': 109,
            'pageUp': 33,
            'pageDn': 34,
            'volUp': 187,
            'volDn': 189,
            'play': 80,
            'pause': 32,
            'stop': 83,
            'playNext': 190,
            'playPrev': 188,
            'mute': 77,
            'red': 82,
            'green': 71,
            'yellow': 89,
            'blue': 66
        },
        /**
         * 是否允许common.log打印
         * @public
         * @example
         *
         * //关闭通过common.log打印的数据
         * common.logable = false
         */
        logable: true,
        /**
         * 通用打印。
         * @description 可以打印object, number, string, boolean, function, null类型的数据。
         * @description 在OWB中会自动以alert()方法输出，object会转换成字符串，无法打印循环引用的object。
         * @description 在chrome中会以console.log方法输出。
         * @public
         * @param {object, number, string, boolean, function, null} data1,data2,...
         * @example
         * common.log({
         *  a: {
         *   b: 1,
         *   c: 2
         *  }
         * }, "string", 314, true, function(){
         * }, null);
         */
        log: function(){
            if (!this.logable) {
                return false;
            }
            var args = arguments;
            if (common.isOWB) {
                for (var i = 0; i < arguments.length; i++) {
                    var item = args[i];
                    if (typeof(item) == "object") {
                        try {
                            args[i] = JSON.stringify(item, null, " ");
                        } 
                        catch (e) {
                            args[i] = "包含循环引用的对象无法打印";
                        }
                    }
                }
                var args = [].join.call(args, "\n");
                alert(args);
            }
            else {
                console.log.apply(console, args);
            }
            return true;
        },
        /**
         * 通用键盘控制管理。
         * @description 不需要new，直接调用。
         * @class
         * @example
         * 注意：被绑定的obj下必须有obj.keyPress(key)函数来响应按键。
         * 如果obj.keyPress类型不为"function"，则绑定失败。
         *
         * $(function(){
         *  common.key.init(); //启用键盘控制
         * 	common.key.change(menu);  //键盘控制权转交给menu
         * })
         */
        key: {
            //当前响应按键的对象列表
            objs: [],
            /**
 * 查询元素在数组中的位置
 * @private
 */
            inArray: function(elem, array){
                if (array.indexOf) {
                    return array.indexOf(elem);
                }
                
                for (var i = 0, length = array.length; i < length; i++) {
                    if (array[i] === elem) {
                        return i;
                    }
                }
                
                return -1;
            },
            /**
 * keyDown响应函数
 * @private
 */
            keyFunc: function(e){
                //common.log("keypress: " + e.keyCode);
                var self = common.key;
                var tempArr = self.objs.concat();
                for (var i = 0; i < tempArr.length; i++) {
                    var obj = tempArr[i];
                    obj.keyPress && obj.keyPress(e.keyCode);
                }
                //过滤以下按键浏览器默认行为,例如切换焦点,发送表单等。
                switch (e.keyCode) {
                    case keyCodeArr.up:
                    case keyCodeArr.down:
                    case keyCodeArr.left:
                    case keyCodeArr.right:
                    case keyCodeArr.enter:
                        return false;
                        break;
                }
            },
            /**
 * 键盘控制初始化
 * @description 如果需要使用本键盘控制功能，则在本对象定义后一次性调用此方法。
 * @public
 * @returns {boolean} 操作是否成功
 * @example
 * $(function(){
 *  common.key.init();
 * })
 */
            init: function(){
                var self = common.key;
                //$(window).keydown(this.keyFunc);
                window.addEventListener("keydown", this.keyFunc, false);
                return true;
            },
            /**
 * 结束键盘控制。
 * @description 执行后将结束使用此功能。（不影响其他用户绑定的keydown响应函数）
 * @public
 * @returns {boolean} 操作是否成功
 * @example
 * $(function(){
 *  common.key.end();
 * })
 */
            end: function(){
                //$(window).unbind("keydown", this.keyFunc);
                window.removeEventListener("keydown", this.keyFunc, false);
                return true;
            },
            /**
 * 改变键盘响应对象。
 * @description 将键盘控制权完全交给obj，obj将是唯一响应按键的对象。
 * @public
 * @param {object} obj 目标对象，该对象下必须包含keyPress键盘响应函数，否则绑定失败。
 * @returns {boolean} 操作是否成功
 * @example
 * menu = {
 *  keyPress: function(key){
 *   ...
 *  }
 * }
 * common.key.change(menu);
 */
            change: function(obj){
                return this.unbind() && this.bind(obj);
            },
            /**
 * 绑定键盘响应对象。
 * @description 添加obj对象按键绑定，可以同时绑定多个。
 * @public
 * @param {object} obj 目标对象，该对象下必须包含keyPress键盘响应函数，否则绑定失败。
 * @returns {boolean} 操作是否成功
 * @example
 * menu = {
 *  keyPress: function(key){
 *   ...
 *  }
 * }
 * common.key.bind(menu);
 */
            bind: function(obj){
                if (!obj || !obj.keyPress || typeof(obj.keyPress) != "function" || this.inArray(obj, this.objs) != -1) {
                    return false;
                }
                this.objs.push(obj);
                return true;
            },
            /**
			 * 解除绑定键盘响应对象。
			 * @description 解除obj对象按键绑定，解除其中一个。
			 * @public
			 * @param {object} obj 目标对象，必须为已绑定的对象，否则解除失败
			 * @returns {boolean} 操作是否成功
			 * @example
			 * menu = {
			 *  keyPress: function(key){
			 *   ...
			 *  }
			 * }
			 * common.key.bind(menu);
			 */
            unbind: function(obj){
                //无参则取消绑定所有
                if (obj == null) {
                    this.objs = [];
                    return true;
                }
                //有参则取消绑定指定obj
                var i = this.inArray(obj, this.objs);
                if (i == -1) {
                    return false;
                }
                this.objs.splice(i, 1);
                return true;
            }
        },
    }
	//兼容全局keyCodeArr
    window.keyCodeArr = common.keyCodeArr;
})();
